package com.example.smart_app;

import androidx.appcompat.app.AppCompatActivity;          //这里是加载的一些库文件
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttAck;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.json.JSONArray;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/*
* 注释区域：
控件：
  按钮
  图片按钮
  文本框
  编辑框
  照片框
  图片
  浏览器框
  地图框
  选择开关
  图片开关

wrap_content  自适应

match_parent 充父控件

LinearLayout：线性布局

再设置id的时候id要保证唯一性
  android:text="确定"
  android:orientation="vertical"   设置布局方向 vertical   代表垂直
  android:orientation="horizontal"    设置布局方向    horizontal   代表   横向
  android:gravity="center"            设置布局方向     center     代表居中
  android:layout_gravity="center"      带layout是针对自己的方式
    android:background="@color/design_default_color_primary"    改变背景颜色

  控件id是Java中文件与xml文件通讯的介质类似于控件的号码  必须唯一
  按钮   实现单击事件
  要实现控件是就必须与按钮的id进行绑定 且id必须唯一

  java里面的函数

  btn_1.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {

           }
       });

  安卓开发要多调式   多刷程序   （因为不知道程序什么时候会崩掉）

  Toast.makeText(MainActivity.this,"你好",Toast.LENGTH_SHORT).show();
  这个程序的意思是单击之后会有一个弹窗提示     ————————>你好。
——*******************************************************************************———
                              控件的联动
——*******************************************************************************————
  ————————————————————————————————————————————————————————————————————————
  EditText 这是一个编辑框
  android:hint="请输入名称"  文本框输入东西

  LinearLayout    带LInear Layout就是针对自己的控件
   android:layout_marginLeft="140dp"   代表本身向左移动的空格
   android:layout_marginTop="20dp"   代表距离顶部的间距
   要实现app之间的控件间距同理
    android:layout_weight="1"     控件实现均分
    ——————————————————————布局是嵌套进行的 一层套一层—————————————————————————----

    ************************************************************************
    *                                                                       *
    *        后期需要用到的东西按钮单击之后用来发送命令控制硬件   例如  open_door      *
    *        文本框更新数据    用来接受硬件上报的传感器的值    例如 温度：36.5°C       *
    *                                                                       *
    *************************************************************************

    举一反三很重要
    需要网络权限  和授权

    网络连接成功
    订阅主题

*****************************************************

MQTT是连接物联网的关键技术，因此这个协议很重要
UI之间反馈信息都靠这个
* */

public class MainActivity extends AppCompatActivity {
    private String host = "tcp://a16dS1AqvFX.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";     //阿里云的域名
    private String userName = "my_app&a16dS1AqvFX";                                          //登录名字
    private String passWord = "d2a0692eedc9af31c5eb6a74299ab6e8391b863a";                    //登录密码
    private String mqtt_id = "my_app|securemode=3,signmethod=hmacsha1,timestamp=789|"; //阿里云的三元组记得和别人不一样 切记！不然会掉线！！！
    private String mqtt_sub_topic = "/sys/a16dS1AqvFX/my_app/thing/service/property/set"; //为了保证你不受到别人的消息    订阅
    private String mqtt_pub_topic = "/sys/a16dS1AqvFX/my_app/thing/event/property/post"; //为了保证你不受到别人的消息   发布
    private int led_flag =1;
    private ScheduledExecutorService scheduler;                                         //处理函数
//    private Button btn_1;  //类似于单片机开发里面的   参数初始化
//    private ImageView image_1;
   // private TextView text_test;
    private MqttClient client;               //mqtt里面的函数    客户端
    private MqttConnectOptions options;     //mqtt的请求报文
    private Handler handler;               // Handler主要用于异步消息的处理： 有点类似辅助类，封装了消息投递、消息处理等接口

    private int baojing_flag ;          //定义报警的 标志位
    private int shuibeng_flag ;         //定义水泵的 标志位
    private int auto_flag ;            //定义自动的 标志位
    private int fan_flag ;             //定义 fan的   标志位

    private TextView wendu;     //温度
    private TextView shidu;     //湿度
    private TextView guangz;    //光照
    private TextView co2;       //co2
    private TextView turang;    //土壤
 //   private TextView rian;      //雨水
    private TextView ph;        //PH值

    private Switch shuibeng;    //水泵开关
    private Switch baojing;     //报警开关
    private Switch auto;        //自动开关
    private Switch fan;         //补光灯的开关

    @SuppressLint("HandlerLeak")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);                 //这里是主要函数运行

        ui_int(); //UI初始化
        auto.setOnClickListener(new View.OnClickListener() {      //事件监听   和ui进行绑定   UI的id是   auto   自动模式
            @Override
            public void onClick(View view) {          //当点击了ui端的开关时   标志位是0   当点击之后  变为  1
                if(auto_flag == 0)

                    {

                        publishmessageplus(mqtt_pub_topic,"{\"params\":{\"AutomaticSwitch\":1 } }");
                     //   publishmessageplus(mqtt_pub_topic,"{\"params\":{\"WaterOutletSwitch\":1 } }");
                        auto_flag =1;    //当点击了ui端的开关时   标志位是0   当点击之后  变为  1
                    }
                else
                    {
                         publishmessageplus(mqtt_pub_topic,"{\"params\":{\"AutomaticSwitch\":0 } }");   //发送的Json格式  控制物理模型
                        auto_flag = 0   ;

                    }
            }
        });


        //报警开关
        baojing.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {              //当点击了ui端的开关时   标志位是0   当点击之后  变为  1
                if(baojing_flag == 0)
                    {                          //   //将要发送的 主题 “{括号里面的内容是上报的格式}”         上报阿里云
                        publishmessageplus(mqtt_pub_topic,"{\"params\":{\"Buzzer\":1 } }");
                      //  publishmessageplus(mqtt_pub_topic,"{\"target\":\"Water\",\"value\":1}");             AutomaticSwitch
                        baojing_flag =1;
                        Toast.makeText(MainActivity.this,"报警已开启",Toast.LENGTH_SHORT).show();    //提示报警已经打开
                    }
                else
                    {

                        publishmessageplus(mqtt_pub_topic,"{\"params\":{\"Buzzer\":0 } }");
                        //publishmessageplus(mqtt_pub_topic,"{\"target\":\"Water\",\"value\":0 }");
                        baojing_flag =0;
                         Toast.makeText(MainActivity.this,"报警已关闭",Toast.LENGTH_SHORT).show();   //Android  弹窗 提示
                    }
                        // Toast.makeText(MainActivity.this,"报警已开启",Toast.LENGTH_SHORT).show();

            }
        });

        //水泵开关
        shuibeng.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(shuibeng_flag == 0)
                {
                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"WaterOutletSwitch\":1 } }");
                    shuibeng_flag =1;
                }
                else
                {
                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"WaterOutletSwitch\":0 } }");
                    shuibeng_flag =0;
                }

            }
        });

        //风扇开关
        fan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(fan_flag == 0)
                {

                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"PowerState\":1 } }");
                    fan_flag = 1 ;
                }
                else
                {

                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"PowerState\":0 } }");

                    fan_flag = 0 ;

                }
            }
        });


//        //补光灯  开关
//        fan.setOnClickListener(new View.OnClickListener() {      //监听事件   LED   补光灯的    监听事件
//            @Override
//            public void onClick(View view) {        //按钮是否被点击
//                if(fan_flag == 0)
//                {
//                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"powerstate\":1}");
//                    fan_flag =1;
//                }
//                else
//                {
//                    publishmessageplus(mqtt_pub_topic,"{\"params\":{\"powerstate\":0}");
//                    fan_flag =0;
//                }
//            }
//        });


        Mqtt_init(); //mqtt初始化

        startReconnect(); //开始连接
        handler = new Handler() {            //mqtt 协议的信息 Handler主要用于异步消息的处理： 有点类似辅助类，封装了消息投递、消息处理等接口。. 当发出一个消息之后，首先进入一个消息队列，发送消息的函数
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 1: //开机校验更新回传
                        break;
                    case 2:  // 反馈回传

                        break;

                    case 3: //MQTT 收到消息回传   UTF8Buffer msg=new UTF8Buffer(object.toString());
                        //湿度     id  shidu
                        //温度

                    //    Toast.makeText(MainActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();

                        String T_val = msg.obj.toString().substring(msg.obj.toString().indexOf("CurrentHumidity\":")+16,msg.obj.toString().indexOf("}"));    //字符提取函数  取出硬件端发来的  温度
                        String shidu1 =  "--------"+T_val;
                        shidu.setText(shidu1);      //将取出来的温度数值发给UI
                        //湿度    CurrentHumidity                ------>   CuTemperature

                        String W_val = msg.obj.toString().substring(msg.obj.toString().indexOf("CuTemperature\":")+14,msg.obj.toString().indexOf("}"));
                        String  wendu1= "--------" +W_val;
                        wendu.setText(wendu1);
                         //光照
                        String G_val = msg.obj.toString().substring(msg.obj.toString().indexOf("mlux\":")+6,msg.obj.toString().indexOf("}"));
                        String  guangzdu= "-------" +G_val;
                        guangz.setText(guangzdu);

                       //c0
                        String C_val = msg.obj.toString().substring(msg.obj.toString().indexOf("coCurrent\":")+10,msg.obj.toString().indexOf("}"));
                        String  co= "-------" +C_val;
                        co2.setText(co);
//
                        //PH
                        String P_val = msg.obj.toString().substring(msg.obj.toString().indexOf("PH\":")+4,msg.obj.toString().indexOf("}"));
                        String  ph1= "--------" +P_val;
                        ph.setText(ph1);
//
//                        //土壤湿度
                        String Tr_val = msg.obj.toString().substring(msg.obj.toString().indexOf("humidity\":")+10,msg.obj.toString().indexOf("}"));
                        String  TR1= "----" +Tr_val;
                        turang.setText(TR1);


                        break;

                    case 30:  //连接失败
                        Toast.makeText(MainActivity.this,"连接失败" ,Toast.LENGTH_SHORT).show();
                        break;
                    case 31:   //连接成功
                        Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show();
                        try {

                           client.subscribe(mqtt_sub_topic,1);

                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        break;
                    default:
                        break;
                }
            }
        };
    }
    //这里是是进行ui初始化
    private void ui_int()
    {
        shuibeng = findViewById(R.id.shuibeng); //和id进行绑定
        baojing = findViewById(R.id.baojing);  //报警开关
        auto = findViewById(R.id.auto);       //自动开关
        fan = findViewById(R.id.fan);        // 风扇控制
        wendu = findViewById(R.id.wendu);
        shidu = findViewById(R.id.shidu);
        guangz = findViewById(R.id.guangz);
        co2 = findViewById(R.id.co2);
        turang = findViewById(R.id.turang);
        ph = findViewById(R.id.ph);    //PH值


    }


 /**************************************************************************************/


    //和mqtt相关的的函数如下    有三个一个初始化   Mqtt连接   mqtt重新连接
    private void Mqtt_init()
    {
        try {
            //host为主机名，test为clientid即连接MQTT的客户端ID，一般以客户端唯一标识符表示，MemoryPersistence设置clientid的保存形式，默认为以内存保存
            client = new MqttClient(host, mqtt_id, new MemoryPersistence());
            //MQTT的连接设置
            options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录，这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(false);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线，但这个方法并没有重连的机制
            options.setKeepAliveInterval(100);
            //设置回调
            client.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    //连接丢失后，一般在这里面进行重连
                    System.out.println("connectionLost----------");
                    //startReconnect();
                }
                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    //publish后会执行到这里
                    System.out.println("deliveryComplete---------"+ token.isComplete());
                }
                @Override
                public void messageArrived(String topicName, MqttMessage message)
                        throws Exception {
                    //subscribe后得到的消息会执行到这里面
                    System.out.println("messageArrived----------");
                    Message msg = new Message();
                    //封装message包
//                    if (msg.obj.toString().equals("CuTemperature"))
//                    {

                        msg.what = 3; // 收到信息标志位   //回传消息的标志位
                        msg.obj = message.toString();     //对象 是
                        handler.sendMessage(msg);   //handler  回传
//                    }


                    //待完善  数据处理  Json格式    详情可去看Json数据解析
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void Mqtt_connect() {                       //mqtt  的连接函数
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if(!(client.isConnected()) )  //如果还未连接
                    {
                        client.connect(options);
                        Message msg = new Message();
                        msg.what = 31;
                        // 没有用到obj字段
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Message msg = new Message();
                    msg.what = 30;
                    // 没有用到obj字段
                    handler.sendMessage(msg);
                }
            }
        }).start();
    }
    private void startReconnect() {
        scheduler = Executors.newSingleThreadScheduledExecutor();   //线程控制用的
        scheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                if (!client.isConnected()) {
                    Mqtt_connect();
                }
            }
        }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
    }
    private void publishmessageplus(String topic,String message2)    //把我们要发送的东西进行封装
    {
        if (client == null || !client.isConnected()) {
            return;
        }
        MqttMessage message = new MqttMessage();
        message.setPayload(message2.getBytes());
        try {
            client.publish(topic,message);
        } catch (MqttException e) {

            e.printStackTrace();
        }
    }

}